// UPD 服务端
#include <iostream>
#include <string>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "log.hpp"
class UDPServer
{
public:
    UDPServer(uint16_t port, std::string ip = "") : _port(port), _ip(ip)
    {
    }
    bool initServer()
    {
        //1. 创建套接字 返回值  套接字的文件描述符
        _socketfd = socket(AF_INET,SOCK_DGRAM,0);
        if(_socketfd < 0 )
        {
            LogMessage(FATAL,"%d,%s",errno,strerror(errno));
            exit(-1);
        }
        //2. bind: 将用户设置的ip和port在内核中和我们当前的进程强关联
        // int bind(int sockfd, const struct sockaddr *addr,
        //        socklen_t addrlen);
        struct sockaddr_in local;
        memset(&local,'0',sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        //支持任意ip访问
        local.sin_addr.s_addr = _ip.empty() ? INADDR_ANY : inet_addr(_ip.c_str());

        int bind_ret = bind(_socketfd,(struct sockaddr*)&local,sizeof(local));
        if(bind_ret < 0)
        {
            LogMessage(FATAL,"%d,%s",errno,strerror(errno));
            exit(-2);
        }

        //success
        LogMessage(NORMAL,"server init success...");
        return true;

    }
    void start()
    {
        //启动服务
        //常驻进程，永不退出
        char buffer[1024];
        while(1)
        {
            
            //peer 纯输出型参数
            struct sockaddr_in peer;
            memset(&peer,0,sizeof(peer));
            memset(buffer,0,sizeof(buffer));
            //peer是缓冲区的大小
            //len实际读到的大小
            socklen_t len = sizeof(peer);

            //从套接字中读取数据
            //ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
            //            struct sockaddr *src_addr, socklen_t *addrlen);
            ssize_t read_size = recvfrom(_socketfd,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&len);
            if(read_size > 0 )//读到数据了
            {
                buffer[read_size] = 0;
                //输出发送的信息
                //发给客户端需要知道ip和端口
                if(strcmp(buffer,"quit") == 0)
                {
                    close(_socketfd);
                    exit(1);
                }
                uint16_t c_port = ntohs(peer.sin_port);
                std::string c_ip = inet_ntoa(peer.sin_addr);
                LogMessage(NORMAL,"%s %d send #: %s",c_ip.c_str(),c_port,buffer);

            }
            //向客户端写回数据
            sendto(_socketfd,buffer,sizeof(buffer) - 1,0,(struct sockaddr*)&peer,len);
        }
    }

    ~UDPServer()
    {
        if(_socketfd > 0 )
        {
            close(_socketfd);
        }
    }

private:
    // 一个服务器，一般必须需要ip地址和port(16位的整数)
    std::string _ip;
    uint16_t _port;
    int _socketfd;
};